#include "stdafx.h"
#include "ScriptObjectBase.h"
#include "DispEx.h"
#include "JSGlobalFunction.h"

// CScriptObject::CScriptObject()
// {
// 	m_spDisp = CreateObject();
// }

CScriptObject::CScriptObject(IWebBrowser2* pWeb, IDispatch* pDisp) 
	: m_spWeb(pWeb)
	, m_spDisp(pDisp)
{
}

CScriptObject::CScriptObject( IWebBrowser2* pWeb ) 
	: m_spWeb(pWeb)
{
	m_spDisp = CreateObject();
}

// CScriptObject::CScriptObject( VARIANT& vDisp )
// {
// 	if (vDisp.vt == VT_DISPATCH)
// 		m_spDisp = vDisp.pdispVal;
// }

IDispatch* CScriptObject::GetDispatch() const
{
	return m_spDisp;
}

IDispatchEx* CScriptObject::GetDispatchEx() const
{
	return m_spDisp;
}

// CScriptControl& CScriptObject::s_GetScriptControl()
// {
// 	static CScriptControl s_sc;
// 	return s_sc;
// }

BOOL CScriptObject::GetValue( BSTR bstrKey, _variant_t& vRet )
{
	BOOL bRet = FALSE;
	try
	{
		DISPID dispID = DISPID_UNKNOWN;
		DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
		
		if (m_spDisp)
		{
			HRESULT hr = m_spDisp->GetDispID(bstrKey, fdexNameCaseSensitive, &dispID);
			if (SUCCEEDED(hr) && dispID != DISPID_UNKNOWN)
			{
				hr = m_spDisp->InvokeEx(dispID,
					LOCALE_USER_DEFAULT,
					DISPATCH_PROPERTYGET, &dispparamsNoArgs, 
					&vRet, NULL, NULL);
				bRet = SUCCEEDED(hr);
			}
		}
	}
	catch (...)
	{
	}

	return bRet;
}

BOOL CScriptObject::SetValue( BSTR bstrKey, _variant_t& vValue )
{
	BOOL bRet = FALSE;

	try
	{
		DISPID dispID = DISPID_UNKNOWN;
		DISPPARAMS dispparams;
		DISPID putid = DISPID_PROPERTYPUT; 
		
		dispparams.rgvarg = &vValue; 
		dispparams.cArgs = 1; 
		dispparams.rgdispidNamedArgs = &putid;
		dispparams.cNamedArgs = 1; 
		
		if (m_spDisp)
		{
			HRESULT hr = m_spDisp->GetDispID(bstrKey, fdexNameCaseSensitive|fdexNameEnsure, &dispID);
			if (SUCCEEDED(hr))
			{
				hr = m_spDisp->InvokeEx(dispID,
					LOCALE_USER_DEFAULT,
					DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF, &dispparams, 
					NULL, NULL, NULL);
				bRet = SUCCEEDED(hr);
			}
		}
	}
	catch (...)
	{
	}

	return bRet;
}

class CFunctor_EnumAllMember
{
public:
	CFunctor_EnumAllMember(std::deque<CComBSTR>& ls) : m_ls(ls) {}

	void operator()(CComBSTR& bstrName)
	{
		m_ls.push_back(bstrName);
	}

private:
	std::deque<CComBSTR>& m_ls;
};

std::deque<CComBSTR> CScriptObject::GetAllMembers()
{
	std::deque<CComBSTR> lsRet;
	CFunctor_EnumAllMember fun(lsRet);
	ForEach(fun);

	return lsRet;
}

BOOL CScriptObject::DeleteValue( BSTR bstrKey )
{
	return SUCCEEDED(m_spDisp->DeleteMemberByName(bstrKey, fdexNameCaseSensitive));
}

void CScriptObject::DeleteAllValues()
{
	std::deque<CComBSTR> ls = GetAllMembers();
	for (size_t i = 0; i < ls.size(); i++)
		DeleteValue(ls[i]);
}

CComPtr<IDispatchEx> CScriptObject::CreateObject()
{
	CComQIPtr<IDispatchEx> spRet;
	if (m_spWeb)
	{
		_variant_t vRet = ExecuteScript(m_spWeb, _T("eval"), _variant_t(_bstr_t("new Object;")));
		if (vRet.vt == VT_DISPATCH && vRet.pdispVal)
		{
			spRet = vRet;
		}
 	}
	return spRet;
}

CScriptObject CScriptObject::CreateScriptObject()
{
	return CScriptObject(m_spWeb);
}

CComPtr<IWebBrowser2> CScriptObject::GetWebBrowser()
{
	return m_spWeb;
}